package com.atguign.gulimall.order.service.impl;

import com.atguign.gulimall.order.config.MqConfig;
import com.atguign.gulimall.order.dao.OrderDao;
import com.atguign.gulimall.order.entity.OrderEntity;
import com.atguign.gulimall.order.entity.OrderItemEntity;
import com.atguign.gulimall.order.entity.PaymentInfoEntity;
import com.atguign.gulimall.order.enume.OrderStatusEnum;
import com.atguign.gulimall.order.feign.CartFeifnService;
import com.atguign.gulimall.order.feign.MemberFeifnService;
import com.atguign.gulimall.order.feign.ProductFeifnService;
import com.atguign.gulimall.order.feign.WareFeifnService;
import com.atguign.gulimall.order.interceptor.LoginUserInterceptor;
import com.atguign.gulimall.order.service.OrderItemService;
import com.atguign.gulimall.order.service.OrderService;
import com.atguign.gulimall.order.service.PaymentInfoService;
import com.atguign.gulimall.order.to.OrderCreateTo;
import com.atguign.gulimall.order.vo.*;
import com.atguigu.common.constant.OrderConstant;
import com.atguigu.common.to.mq.SeckillOrderTo;
import com.atguigu.common.utils.PageUtils;
import com.atguigu.common.utils.Query;
import com.atguigu.common.utils.R;
import com.atguigu.common.vo.MemberEntityVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service("orderService")
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {

    @Autowired
    MemberFeifnService memberFeifnService;
    @Autowired
    CartFeifnService cartFeifnService;
    @Autowired
    WareFeifnService wareFeifnService;
    @Autowired
    ProductFeifnService productFeifnService;
    @Autowired
    ThreadPoolExecutor executor;
    @Autowired
    StringRedisTemplate redisTemplate;
    @Autowired
    OrderItemService orderItemService;
    @Autowired
    RabbitTemplate rabbitTemplate;
    @Autowired
    PaymentInfoService paymentInfoService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<OrderEntity> page = this.page(new Query<OrderEntity>().getPage(params), new QueryWrapper<OrderEntity>());
        return new PageUtils(page);
    }

    @Override
    public OrderConfirmVo confirmOrder() {
        OrderConfirmVo orderConfirmVo = new OrderConfirmVo();
        MemberEntityVo memberEntityVo = LoginUserInterceptor.threadLocal.get();
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); // 获取当前线程的请求
        CompletableFuture<Void> getAddress = CompletableFuture.runAsync(() -> {
            RequestContextHolder.setRequestAttributes(requestAttributes); // 将当前线程的请求赋值给子线程
            R list = memberFeifnService.list(memberEntityVo.getId());
            if (list.getCode() == 0) {
                orderConfirmVo.setAddress(R.toListPoJo(list.get("data"), MemberReceiveAddressEntityVo.class));
            }
        }, executor);
        CompletableFuture<Void> getItems = CompletableFuture.runAsync(() -> {
            RequestContextHolder.setRequestAttributes(requestAttributes);
            R r = cartFeifnService.currentUserCartItems();
            if (r.getCode() == 0) {
                orderConfirmVo.setItems(R.toListPoJo(r.get("data"), OrderItemVo.class));
            }
        }, executor).thenRunAsync(() -> {
            List<OrderItemVo> items = orderConfirmVo.getItems();
            List<Long> collect = items.stream().map(OrderItemVo::getSkuId).collect(Collectors.toList());
            R skusHasStock = wareFeifnService.getSkusHasStock(collect);
            log.debug("库存查询结果：" + skusHasStock);
            if (skusHasStock.getCode() == 0) {
                List<SkuHasStockTo> data = R.toListPoJo(skusHasStock.get("data"), SkuHasStockTo.class);
                HashMap<Long, Boolean> hasStockMap = new HashMap<>();
                data.forEach(item -> {
                    hasStockMap.put(item.getSkuId(), item.getStock() > 0);
                });
                for (OrderItemVo item : items) {
                    Boolean b = hasStockMap.get(item.getSkuId());
                    item.setHasStock(b != null && b);
                }
            }
        }, executor);
        CompletableFuture<Void> getIntegration = CompletableFuture.runAsync(() -> {
            RequestContextHolder.setRequestAttributes(requestAttributes);
            R integration = memberFeifnService.integration(memberEntityVo.getId());
            if (integration.getCode() == 0) {
                orderConfirmVo.setIntegration(new Integer(integration.get("data").toString()));
            }
        }, executor);
        try {
            String replace = UUID.randomUUID().toString().replace("-", "");
            orderConfirmVo.setOrderToken(replace);
            redisTemplate.opsForValue().set(OrderConstant.USER_ORDER_TOKEN_PREFIX + memberEntityVo.getId(), replace, 30, TimeUnit.MINUTES);
            CompletableFuture.allOf(getAddress, getItems, getIntegration).get();
        } catch (InterruptedException | ExecutionException e) {
            log.error("获取订单确认页信息异常", e);
            throw new RuntimeException(e);
        }
        return orderConfirmVo;
    }
//    @GlobalTransactional   高并发性能差
    @Transactional
    @Override
    public SubmitOrderResponseVo submitOrder(SubmitOrderVo submitOrderVo) {
        SubmitOrderResponseVo responseVo = new SubmitOrderResponseVo();
        responseVo.setCode(1);
        //验证令牌
        MemberEntityVo memberEntityVo = LoginUserInterceptor.threadLocal.get();
        String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
        Long lock = redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class), Collections.singletonList(OrderConstant.USER_ORDER_TOKEN_PREFIX + memberEntityVo.getId()), submitOrderVo.getOrderToken());
        if (lock == 0L) {
            log.debug("订单被锁定");
            throw new RuntimeException("令牌校验失败");
        } else {
            OrderCreateTo order = createOrder(submitOrderVo, memberEntityVo);
            //对比金额
            BigDecimal payAmount = order.getOrder().getPayAmount();
            BigDecimal abs = payAmount.subtract(submitOrderVo.getPayPrice()).abs();
            if (abs.compareTo(new BigDecimal("0.01")) < 0) {
                //保存订单
                saveOrder(order);


                //锁库存
                WareSkuLockVo wareSkuLockVo = new WareSkuLockVo();
                wareSkuLockVo.setOrderSn(order.getOrder().getOrderSn());
                wareSkuLockVo.setLocks(order.getOrderItems().stream().map(item -> {
                    OrderItemVo orderItemVo = new OrderItemVo();
                    orderItemVo.setSkuId(item.getSkuId());
                    orderItemVo.setCount(item.getSkuQuantity());
                    orderItemVo.setTitle(item.getSkuName());
                    orderItemVo.setPrice(item.getSkuPrice());
                    return orderItemVo;
                }).collect(Collectors.toList()));
                R r = wareFeifnService.orderLockStock(wareSkuLockVo);
                if (r.getCode() == 0) {
                    log.debug("锁定库存成功");
                    responseVo.setOrder(order.getOrder());
                    responseVo.setCode(0);
                    //TODO 发送消息给mq
                    rabbitTemplate.convertAndSend(MqConfig.ORDER_EVENT_EXCHANGE, "order.create.order", order.getOrder());
                }else{
                    log.debug("锁定库存失败");
                    responseVo.setCode(1);
                    throw new RuntimeException("锁定库存失败");
                }
            } else {
                responseVo.setCode(2);
                log.debug("比价失败");
                throw new RuntimeException("比价失败");
            }
        }
        return responseVo;
    }

    @Override
    public OrderEntity getOrderByOrderSn(String orderSn) {
        return this.baseMapper.selectOne(new LambdaQueryWrapper<OrderEntity>().eq(OrderEntity::getOrderSn, orderSn));
    }

    @Override
    public PageUtils queryPageWithItem(Map<String, Object> params) {
        MemberEntityVo memberEntityVo = LoginUserInterceptor.threadLocal.get();
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new LambdaQueryWrapper<OrderEntity>()
                        .eq(OrderEntity::getMemberId, memberEntityVo.getId())
                        .orderByDesc(OrderEntity::getCreateTime)
        );
        page.getRecords().forEach(order -> {
            List<OrderItemEntity> list = orderItemService.list(new LambdaQueryWrapper<OrderItemEntity>().eq(OrderItemEntity::getOrderSn, order.getOrderSn()));
            order.setItems(list);
        });

        return new PageUtils(page);
    }

    /**
     * 支付成功回调
     * @param vo
     * @return
     */
    @Transactional
    @Override
    public String hadlePayResult(PayAsyncVo vo) {
        PaymentInfoEntity paymentInfoEntity = new PaymentInfoEntity();
        paymentInfoEntity.setAlipayTradeNo(vo.getTrade_no());
        paymentInfoEntity.setOrderSn(vo.getOut_trade_no());
        paymentInfoEntity.setPaymentStatus(vo.getTrade_status());
        paymentInfoEntity.setCallbackTime(vo.getNotify_time());
        paymentInfoService.save(paymentInfoEntity); //支付流水
        if(vo.getTrade_status().equals("TRADE_SUCCESS")){
            this.updateOrderStatus(vo.getOut_trade_no(), OrderStatusEnum.PAYED.getCode());
        }
        return "success";
    }
    @Transactional
    @Override
    public void createSeckillOrder(SeckillOrderTo seckillOrderTo) {
        OrderEntity orderEntity = new OrderEntity();
        orderEntity.setOrderSn(seckillOrderTo.getOrderSn());
        orderEntity.setPayAmount(seckillOrderTo.getSeckillPrice().multiply(new BigDecimal(seckillOrderTo.getNum().toString())));
        orderEntity.setMemberId(seckillOrderTo.getMemberId());
        orderEntity.setStatus(OrderStatusEnum.CREATE_NEW.getCode());
        this.save(orderEntity);


        OrderItemEntity orderItemEntity = new OrderItemEntity();
        orderItemEntity.setOrderSn(seckillOrderTo.getOrderSn());
        orderItemEntity.setSkuId(seckillOrderTo.getSkuId());
        orderItemEntity.setRealAmount(seckillOrderTo.getSeckillPrice());
        orderItemEntity.setSkuQuantity(seckillOrderTo.getNum());

        orderItemService.save(orderItemEntity);
    }

    /**
     * 订单修改标签
     * @param outTradeNo
     * @param code
     */
    private void updateOrderStatus(String outTradeNo, Integer code) {
        this.baseMapper.update(new LambdaUpdateWrapper<OrderEntity>()
                .set(OrderEntity::getStatus, code)
                .eq(OrderEntity::getOrderSn, outTradeNo)
                .eq(OrderEntity::getStatus, OrderStatusEnum.CREATE_NEW.getCode()));
    }


    /**
     * 保存订单
     *
     * @param order
     */

    private void saveOrder(OrderCreateTo order) {
        OrderEntity order1 = order.getOrder();
        order1.setModifyTime(new Date());
        this.save(order1);
        List<OrderItemEntity> orderItems = order.getOrderItems();
        orderItemService.saveBatch(orderItems);
    }

    /**
     * 创建订单
     * @param submitOrderVo
     * @param memberEntityVo
     * @return
     */
    private OrderCreateTo createOrder(SubmitOrderVo submitOrderVo, MemberEntityVo memberEntityVo) {
        OrderCreateTo orderCreateTo = new OrderCreateTo();

        OrderEntity orderEntity = bulidOrder(submitOrderVo, memberEntityVo);//订单信息
        List<OrderItemEntity> orderItemEntities = budidOrderItems(orderEntity.getOrderSn(), memberEntityVo); //订单项信息
        orderCreateTo.setOrderItems(orderItemEntities);
        orderCreateTo.setOrder(orderEntity);
        computePrice(orderEntity, orderItemEntities);

        return orderCreateTo;
    }

    /**
     * 计算价格
     * @param orderEntity
     * @param orderItemEntities
     */
    private void computePrice(OrderEntity orderEntity, List<OrderItemEntity> orderItemEntities) {
        BigDecimal total = new BigDecimal("0"); //优惠前的价格
        BigDecimal couponAmount = new BigDecimal("0");
        BigDecimal integrationAmount = new BigDecimal("0");
        BigDecimal promotionAmount = new BigDecimal("0");

        Integer giftGrowth = 0;
        for (OrderItemEntity orderItemEntity : orderItemEntities) {
            total = total.add(orderItemEntity.getRealAmount());
            couponAmount = couponAmount.add(orderItemEntity.getCouponAmount());
            integrationAmount = integrationAmount.add(orderItemEntity.getIntegrationAmount());
            promotionAmount = promotionAmount.add(orderItemEntity.getPromotionAmount());

            giftGrowth += orderItemEntity.getGiftGrowth();
        }
        orderEntity.setTotalAmount(total);
        orderEntity.setPayAmount(total.add(orderEntity.getFreightAmount()));
        orderEntity.setPromotionAmount(promotionAmount);
        orderEntity.setIntegrationAmount(integrationAmount);
        orderEntity.setCouponAmount(couponAmount);

        orderEntity.setGrowth(giftGrowth);

    }

    /**
     * 构建订单
     *
     * @param submitOrderVo
     * @return
     */
    private OrderEntity bulidOrder(SubmitOrderVo submitOrderVo, MemberEntityVo memberEntityVo) {
        OrderEntity orderEntity = new OrderEntity();
        String timeId = IdWorker.getTimeId();
        orderEntity.setOrderSn(timeId);
        orderEntity.setMemberId(memberEntityVo.getId());
        orderEntity.setMemberUsername(memberEntityVo.getUsername());

        R fare = wareFeifnService.getFare(submitOrderVo.getAddressId());
        if (fare.getCode() == 0) {
            FareVo fareVo = R.toPoJo(fare.get("data"), FareVo.class);
            orderEntity.setFreightAmount(fareVo.getFare());
            orderEntity.setReceiverCity(fareVo.getAddress().getCity());
            orderEntity.setReceiverDetailAddress(fareVo.getAddress().getDetailAddress());
            orderEntity.setReceiverName(fareVo.getAddress().getName());
            orderEntity.setReceiverPhone(fareVo.getAddress().getPhone());
            orderEntity.setReceiverPostCode(fareVo.getAddress().getPostCode());
            orderEntity.setReceiverProvince(fareVo.getAddress().getProvince());
            orderEntity.setReceiverRegion(fareVo.getAddress().getRegion());


            orderEntity.setStatus(OrderStatusEnum.CREATE_NEW.getCode());
            orderEntity.setDeleteStatus(0);
            return orderEntity;
        }
        return null;
    }

    /**
     * 构建订单项信息
     *
     * @return
     */

    private List<OrderItemEntity> budidOrderItems(String orderId, MemberEntityVo memberEntityVo) {
        R r = cartFeifnService.currentUserCartItems();
        if (r.getCode() == 0) {
            List<CartItemVo> data = R.toListPoJo(r.get("data"), CartItemVo.class);
            if (data != null && !data.isEmpty()) {
                return data.stream().map(item -> buildOrderItem(orderId, item)).collect(Collectors.toList());
            }
        }
        return null;
    }

    private OrderItemEntity buildOrderItem(String orderId, CartItemVo item) {
        OrderItemEntity orderItemEntity = new OrderItemEntity();
        orderItemEntity.setOrderSn(orderId);

        //sku信息
        orderItemEntity.setSkuId(item.getSkuId());
        orderItemEntity.setSkuName(item.getTitle());
        orderItemEntity.setSkuPic(item.getImage());
        orderItemEntity.setSkuPrice(item.getPrice());
        orderItemEntity.setSkuAttrsVals(StringUtils.collectionToDelimitedString(item.getSkuAttr(), ";"));
        orderItemEntity.setSkuQuantity(item.getCount());
        //积分
        orderItemEntity.setGiftIntegration(item.getPrice().multiply(BigDecimal.valueOf(item.getCount())).intValue());
        orderItemEntity.setGiftGrowth(item.getPrice().multiply(BigDecimal.valueOf(item.getCount())).intValue());
        //spu信息
        R spuInfoBySkuId = productFeifnService.getSpuInfoBySkuId(item.getSkuId());
        if (spuInfoBySkuId.getCode() == 0) {
            SpuInfoEntityVo spuInfoEntity = R.toPoJo(spuInfoBySkuId.get("data"), SpuInfoEntityVo.class);
            orderItemEntity.setSpuId(spuInfoEntity.getId());
            orderItemEntity.setCategoryId(spuInfoEntity.getCatalogId());
            orderItemEntity.setSpuName(spuInfoEntity.getSpuName());
            orderItemEntity.setSpuBrand(spuInfoEntity.getBrandId().toString());
        }

        //价格信息
        orderItemEntity.setPromotionAmount(BigDecimal.ZERO);
        orderItemEntity.setCouponAmount(BigDecimal.ZERO);
        orderItemEntity.setIntegrationAmount(BigDecimal.ZERO);
        orderItemEntity.setRealAmount(item.getPrice().multiply(BigDecimal.valueOf(item.getCount())).subtract(orderItemEntity.getPromotionAmount()).subtract(orderItemEntity.getCouponAmount()).subtract(orderItemEntity.getIntegrationAmount()));
        return orderItemEntity;
    }


}